home *** CD-ROM | disk | FTP | other *** search
/ Developer Helper 1: Phil & Dave's Excellent CD / Excellent CD HFS.raw / Utilities / Apple File Exchange / AppleFile Exchange Translator / ExampleTrans / Example.p < prev    next >
Text File  |  1989-04-13  |  49KB  |  1,333 lines

  1. unit TransExample;
  2.  
  3. (*
  4.  *_____________________________________________________________________
  5.  *
  6.  *    File: Example.p
  7.  *
  8.  *        Copyright 1986,1987 by Apple Computer, Inc.  All Rights Reserved.
  9.  *_____________________________________________________________________
  10.  *
  11.  *    Example translator between Macintosh, ProDOS, and MS-DOS.
  12.  *
  13.  *        Written by Karl B. Young
  14.  *
  15.  *_____________________________________________________________________
  16.  *
  17.  *    Revision History
  18.  *
  19.  *        16-Jul-87        1.0A1        New today
  20.  *_____________________________________________________________________
  21.  *
  22.  * 
  23.  *_____________________________________________________________________
  24.  *)
  25.  { This translator opens up the resource fork of a Macintosh file and copies *
  26.  * all resources of the type STR# to a text file on any of the file systems. *
  27.  * If the translation is Mac to Mac a dialog box is available to set the      *
  28.  * creator type of the text file (to open it just double click on it ).         *
  29.  * Note that this dialog box is only available when the translator is in the *
  30.  * Mac to Mac menu, in the other menus it will not appear since Mac creator  *
  31.  * types have no meaning in the other file systems.  Also notice how this    *
  32.  * translator protects itself from being loaded into menus in which it has no*
  33.  * usefulness.   *}
  34.                             INTERFACE
  35.                             
  36. USES 
  37. {$LOAD MacLoad.L}    MemTypes,QuickDraw,osIntf,toolIntf,packIntf,macPrint,script,
  38. {$LOAD }            AFETrans; 
  39. { AFETrans contains all of the standard AFE data structure definitions }
  40.  
  41. { This is the function through which AFE communicates with the translator }
  42. function TranStr(Message : integer; VAR TranslateData : Handle;
  43.         Param : longint; Self : handle) : longint;
  44.  
  45.                         IMPLEMENTATION
  46. {$R-}
  47.  
  48. CONST
  49.  
  50.     {************************************************************************
  51.      *                                                                         *
  52.      * constants for strings (for error messages)                            *
  53.      * the order of these strings is the same as in Example.r                *
  54.      *                                                                        *
  55.      ***********************************************************************}
  56.     str_error        = 1; {  "An error occurred while " }
  57.     str_creating    = 2; {  "creating the destination file: " }
  58.     str_opensrc        = 3; {  "opening the source file: " }
  59.     str_opendst        = 4; {  "opening the destination file: " }
  60.     str_getfinfo    = 5; {  "getting information about the file: " }
  61.     str_setfinfo    = 6; {  "setting the file type of the destination file: " }
  62.     str_reading        = 7; {  "reading in the source file: " }
  63.     str_writing        = 8; {  "writing out the destination file: " }
  64.     str_copying        = 9; {  "Copying STR# resources…" }
  65.     str_initing        = 10; { "initializing the translator " }
  66.     str_period        = 11; { "." }
  67.     str_cant        = 12; { "It cannot translate from " }
  68.     str_to            = 13; { " to " }
  69.     str_delsrc        = 14; { "deleting the original file (your translated data is in the file $$$AFE-TEMP$$$): " }
  70.     str_rendst        = 15; { "renaming the destination file (your translated data is in the file $$$AFE-TEMP$$$): "}
  71.     str_numstrings    = 16; { "Number of STR# resources in this file: " }
  72.     str_stringRes    = 17; { "String Resource number " }
  73.  
  74.     {************************************************************************
  75.      *                                                                         *
  76.      * constants for dialog box                                                *
  77.      * these are the item numbers for the objects in the options dialog box    *
  78.      *                                                                        *
  79.      ***********************************************************************}
  80.     d_OK            = 1;
  81.     d_Cancel        = 2;
  82.     d_text            = 3;
  83.     d_MWradio        = 4;
  84.     d_MSWradio        = 5;
  85.     d_MPWradio        = 6;
  86.     d_MDSradio        = 7;
  87.     d_otherRadio    = 8;
  88.     d_MWicon        = 9;
  89.     d_MSWicon        = 10;
  90.     d_MPWicon        = 11;
  91.     d_MDSicon        = 12;
  92.     d_otherText        = 13;
  93.  
  94.     {************************************************************************
  95.      *                                                                         *
  96.      * Miscellaneous Constants                                                *
  97.      *                                                                        *
  98.      ***********************************************************************}
  99.     tMCMC = 1;        { Mac to Mac translation }
  100.     tMCPD = 2;        { Mac to ProDOS translation }
  101.     tMCMS = 3;        { Mac to MS-DOS translation }
  102.     
  103.     {************************************************
  104.     * The following are offsets from the MacWrite     *
  105.     * button in the options dialog box                *
  106.     ************************************************}
  107.     tMacWrite = 0;    { MacWrite }
  108.     tMSWord = 1;    { Microsoft Word }
  109.     tMPW = 2;        { MPW }
  110.     tMDS = 3;        { MDS 68000 }
  111.     tother = 4;        { other }
  112.     
  113.     {************************************************
  114.     * The following are creator names for the apps     *
  115.     * in the options dialog box                        *
  116.     ************************************************}
  117.     fMacWrite     = 'MACA'; { MacWrite }
  118.     fMSWord     = 'MWRD'; { Microsoft Word }                     
  119.     fMPW        = 'MPS '; { MPW }
  120.     fMDS        = 'EDIT'; { MDS 68000 }
  121.  
  122.     fromFS = 0; { denotes the source file system }
  123.     toFS = 1;    { denotes the destination file system }
  124.     
  125. TYPE
  126.     {This data type is used to hold the File system nicknames, MC,MS,PD. }
  127.     halfResType = packed array[1..2] of char;
  128.  
  129. {*************** Global Variables record **************}
  130.     StatusRec = RECORD
  131.         mystatus : longint; { keeps the status bits for the translator,
  132.                               see discussion about TranData in the manual }
  133.         myID : integer;        { ID number of the STR# resource containing 
  134.                               error strings }
  135.         myfref : integer;    { The file reference number for my resource file }
  136.         trankind : integer;    { The type of translation occurring, eg Mac to Mac}
  137.         ftype : OSType;        { The creator name for the destination file }        
  138.         fkind : integer;    { the offset from the MacWrite dialog button }
  139.         frHandle : Handle;    { handle to the source file system resource }
  140.         toHandle : Handle;    { handle to the destination file system }
  141.         srcsize : longint;    { byte size of the source file }
  142.         end;
  143.     StatPtr = ^StatusRec;
  144.     StatHndl = ^StatPtr;
  145.  
  146. { Listing of all the functions in this unit }
  147. Function  Activate(statRec : statHndl; trnPB : trnPtr) : longint; Forward;
  148. Function  CopyFile(srcref,dstref : integer; statRec : statHndl; trnPB : trnPtr) : OSErr; Forward;
  149. Function  DoAppear(trnpb : trnptr; statRec : statHndl) : longint; Forward;
  150. Function  DoFileConvert(statRec : statHndl; trnPB : trnPtr) : longint; Forward;
  151. Function  DoFinish(VAR translateData : handle) : OSErr; Forward;
  152. Function  DoInit(VAR translateData,self : handle; trnpb : trnPtr) : longint; Forward;
  153. Function  DoName(statRec : statHndl; trnPB : trnPtr) : longint; Forward;
  154. Function  FileIO(ff,fs : integer; pb : HParmBlkPtr; statrec : StatHndl; trnPB : trnPtr) : OSErr; Forward;
  155. Function  FileOp(ff,fs : integer; pb : HParmBlkPtr; statrec : StatHndl; trnPB : trnPtr) : OSErr; Forward;
  156. Function  GetStrSize(fref : integer) : longint; Forward;
  157. Function  RecogFile(statRec : statHndl; trnPB : trnPtr) : longint; Forward;
  158. Procedure ReportErr(err,doing : integer; statRec : statHndl; trnPB : trnPtr); Forward;
  159.  
  160.  
  161.  {*************************** Activate **************************************
  162.  * Called when translator receives a trn_Activate.
  163.  * ACTIVATE indicates that the user wishes to check this menu item.  The    *
  164.  * routine does whatever it wants (usually just setting the appropriate bit    *
  165.  * in the flags, but it could be as complicated as a dialog box prompting    * 
  166.  * the user for options), and then returns the new status flag as the        *
  167.  * function result. In this case Activate only puts up a dialog box if it is* 
  168.  * being activated in the Mac to Mac menu; otherwise it just updates the    *
  169.  * active bit in the status variable.                                        *
  170.  * Notice how the dialog box is only activated for the Mac to Mac trans-    *
  171.  * lation. For the other translation the we just set the active bit.        *
  172.  ***************************************************************************}
  173. Function  Activate(statRec : statHndl; trnPB : trnPtr) : longint;
  174.     var
  175.         user_ptr : dialogPtr;
  176.         cHndl : Controlhandle;
  177.         itype : integer; { type of item in the dialog box,see Inside Mac 
  178.                            vol I for details}
  179.         iHndl : handle;  { a handle to an item }
  180.         irect : rect;     { the display rectangle for the item }
  181.         i : integer;
  182.         str : str255;
  183.         item : integer;
  184.         curfkind : integer; { the current destination file type }
  185.         oldres : integer;
  186.     begin
  187.     { if the translation is to prodos or msdos }
  188.     if statrec^^.tranKind > tMCMC
  189.         then statRec^^.mystatus := bor(trnActive,statRec^^.mystatus)
  190.     else if statrec^^.tranKind = tMCMC then begin
  191.     { if the translation is Mac to Mac than get the option dialog box }
  192.         oldres := curResFile; { in case another resource file is being used }
  193.         useResFile(statRec^^.myFref);
  194.         user_ptr := getNewDialog(statRec^^.myID,nil,POINTER(-1));
  195.         useResFile(oldres); { restore the old res file }
  196.         
  197.         { set up the file type }
  198.         str := '    ';
  199.         { check that the file type only consists of printable ascii characters }
  200.         for i := 1 to 4 do begin
  201.             if statRec^^.ftype[i] in [' '..'~'] 
  202.                 then str[i] := statRec^^.ftype[i];
  203.             end;
  204.         getDItem(user_ptr,d_otherText,itype,iHndl,iRect);
  205.         setIText(iHndl,str);
  206.         
  207.         { set up the radio button }
  208.         { get the previously selected file type, this is an offset from MacWrite}
  209.         curfkind := statrec^^.fkind;
  210.         { get a handle to that item }
  211.         getDItem(user_ptr,d_MWradio+curfkind,itype,iHndl,iRect);
  212.         cHndl := POINTER(iHndl);
  213.         { turn the button to that item on }
  214.         SetCtlValue(cHndl,1);
  215.         { display the dialog box on the screen }
  216.         showWindow(user_ptr);
  217.  
  218.         repeat
  219.             { wait for a click in the dialog box }
  220.             modalDialog(NIL,item);
  221.             { if click anywhere except OK or Cancel }
  222.             if item in [d_MWradio..d_otherText] then begin
  223.                 { if clicked on document icon calculate to which radio button }
  224.                 { it belongs. }
  225.                 if item >= d_MWicon then item := d_MWradio + (item - d_MWicon);
  226.                 { if the new choice is not the same as the old choice }
  227.                 if curfkind <> (item - d_MWradio) then begin
  228.                     { get a handle to the old item }
  229.                     getDItem(user_ptr,d_MWradio+curfkind,itype,iHndl,iRect);
  230.                     cHndl := POINTER(iHndl);
  231.                     { turn its radio button off }
  232.                     SetCtlValue(cHndl,0);
  233.                     { get a handle to the new item }
  234.                     getDItem(user_ptr,item,itype,iHndl,iRect);
  235.                     cHndl := POINTER(iHndl);
  236.                     { turn its radio button on }
  237.                     SetCtlValue(cHndl,1);
  238.                     { calculate the new offset from MacWrite }
  239.                     curfkind := item - d_MWradio;
  240.                     { if the Other radio button is not highlighted then put }
  241.                     { the apporiate creator type in the text box }
  242.                     if curfkind < tother then begin
  243.                         case curfKind of
  244.                             tMacWrite     : str := fMacWrite;
  245.                             tMSWord     : str := fMSWord;
  246.                             tMPW        : str := fMPW;
  247.                             tMDS        : str := fMDS;
  248.                             end;
  249.                         getDItem(user_ptr,d_otherText,itype,iHndl,iRect);
  250.                         SetIText(iHndl,str);
  251.                         end;
  252.                     end;
  253.                 end;
  254.             until item in [d_OK,d_Cancel];
  255.         
  256.         if item = d_OK then begin
  257.             { save the destination file type in the Global variable }
  258.             statrec^^.fkind := curfKind;
  259.             getDItem(user_ptr,d_otherText,itype,iHndl,iRect);
  260.             GetIText(iHndl,str);
  261.             { Make sure that the file type is four characters long }
  262.             statrec^^.ftype := '    ';
  263.             { Take only the first four characters of the file type }
  264.             for i := 1 to 4 do begin
  265.                 if length(str) >= i
  266.                     then statrec^^.ftype[i] := str[i];
  267.                 end;
  268.             { Set the Active bit in the status variable }    
  269.             statRec^^.myStatus := bor(statRec^^.myStatus,trnActive);
  270.             end;
  271.             
  272.         DisposDialog(user_ptr);
  273.         end;
  274.     { Return the current translator status. }
  275.     Activate := statRec^^.myStatus;
  276.     end; { Activate }
  277.  
  278. {* This is the function that actually does the translation of the STR# re-  *
  279.  *  source to a text file.
  280. INPUT : srcref,dstref - file reference numbers for the source and destination
  281.                         file.
  282.         datasize  - the size of the source file
  283.         statRec   - the Global variable record.
  284. RESULT: The sucess or failure of the translation.
  285. USED by : DoFileConvert 
  286. * Notice its use of tprocs to transliterate between the various character
  287. * sets used by the different file systems. Also notice that whenever tprocs
  288. * are called we make sure it is loaded in memory by using LoadResource, just
  289. * because we have a handle to it does not mean it resides currently in 
  290. * memory because it is a purgeable resource.
  291. *}
  292. Function  CopyFile(srcref,dstref : integer; statRec : statHndl; trnPB : trnPtr) : OSErr;
  293.     var
  294.         oldres : integer;
  295.         numstr,numentries : integer;
  296.         s,n : integer;
  297.         hstr : handle;
  298.         numptr : ^integer;
  299.         str : str255;
  300.         theID : integer;
  301.         theType : ResType;
  302.         theName : str255;
  303.         datasize : longint;
  304.         buf : array[0..511] of signedbyte;
  305.         bufsize : integer;
  306.         pb : ParamBlockRec;
  307.         tpb : transPB;
  308.         tproc : hdrHndl;
  309.     
  310.     {* This procedure finds the desired TProc for the transliteration 
  311.      * between the Mac and one of the other file systems  and intializes it
  312.      *}
  313.     Procedure GetTProc;
  314.         var
  315.             tp : tprfHndl;
  316.             found : boolean;
  317.             entry : integer;
  318.             i : integer;
  319.             loCharSet,hiCharSet : integer;
  320.             theverb : integer;
  321.             theflag : integer;
  322.             err : OSErr;
  323.         begin
  324.         tproc := NIL;
  325.         { One doesn't need a Tproc if the translation involves only one 
  326.           computer type }
  327.         if statrec^^.trankind = tMCMC then exit(GetTProc);
  328.         { get a handle to the  Tproc family for the given source country,
  329.           if more than one trpf is available the user chooses which one to 
  330.           use from the country menu provided by AFE. }
  331.         tp := POINTER(getResource('tprf',trnpb^.trncountry));
  332.         if tp = NIL then exit(GetTProc);
  333.         case statrec^^.tranKind of
  334.             tMCPD : begin
  335.                 loCharSet := cfMacintosh;
  336.                 hiCharSet := cfASCII;
  337.                 theverb := transLotoHi;
  338.                 theflag := trNonOnetoOne;
  339.                 end;
  340.             tMCMS : begin
  341.                 loCharSet := cfMacintosh;
  342.                 hiCharSet := cfIBMPC;
  343.                 theverb := transLotoHi;
  344.                 theflag := trNonOnetoOne;
  345.                 end;
  346.             end;
  347.         found := false;        
  348.         { Search through the whole tproc family for the one that translates
  349.           between the two character families }
  350.         for i := 1 to tp^^.lastentry do with tp^^.tprocs[i] do begin
  351.             if altcountry = trnpb^.trncountry then
  352.                 if (curCharFam = loCharSet) and (altCharFam = hiCharSet) then begin
  353.                     found := true;
  354.                     entry := i;
  355.                     leave;
  356.                     end;
  357.             end;
  358.         if not found then exit(GetTProc);
  359.         { Get a handle to the tproc specified by the tproc family entry }
  360.         tproc := POINTER(GetResource('tprc',tp^^.tprocs[entry].tprcID));
  361.         { exit if the resource cannot be found }
  362.         if tproc = NIL then exit(GetTProc);
  363.         { if not currently in memory thant load it now }
  364.         if tproc^ = NIL then loadResource(POINTER(tproc));
  365.         with tpb do begin
  366.             featureflags := band(tproc^^.flags,theflag);
  367.             newcntry := -1;
  368.             { these fields are reserved set to zero }
  369.             tpRsrv[0] := 0;
  370.             tpRsrv[1] := 0;
  371.             tpRsrv[2] := 0;
  372.             tpRsrv[3] := 0;
  373.             { initialize transliteration procedure }
  374.             verb := transInit;
  375.             err := CallTProc(tpb,tproc);
  376.             if err <> noerr then begin
  377.                 tproc := NIL;
  378.                 exit(GetTProc);
  379.                 end;
  380.             { the translations will be transLotoHigh }
  381.             verb := theverb;
  382.             end;
  383.         end;
  384.  
  385.  
  386.     {* This procedure send the source string to the Transliteration 
  387.      * procedure and returns the result in tpb.dstText.trPtr. The verb for
  388.      * the translation was set in GetTProc.
  389.      * OUTPUT : Bufsize is changed to be the size of the destination 
  390.      *            buffer. It is used in WriteString.
  391.      *}
  392.     Procedure TranslitString(VAR str : str255);
  393.         var
  394.             err : OSErr;
  395.         begin
  396.         { if there is no tproc than just move the source buffer to the 
  397.           ioBuffer buffer }
  398.         if tProc = NIL then begin
  399.             blockmove(POINTER(ORD4(@str)+1),@buf,length(str));
  400.             bufsize := length(str);
  401.             end
  402.         else begin
  403.             tpb.srcText.trLen := length(str);
  404.             { The first element of a string is its size, since we do not
  405.               want to translate this character we set the buffer to the 
  406.               next one. }
  407.             tpb.srcText.trPtr := POINTER(ORD4(@str)+1);
  408.             tpb.srcText.trFont := 0;
  409.             tpb.dstText.trLen := 512;
  410.             tpb.dstText.trPtr := @buf;
  411.             tpb.dstText.trFont := 0;
  412.             {if the tproc is not in memory than load it }
  413.             if tproc^ = NIL then loadResource(POINTER(tproc));
  414.             err := CallTProc(tpb,tProc);
  415.             bufsize := tpb.dstText.trLen;
  416.             end;
  417.         end;
  418.     
  419.     {* This procedure writes out a string to the destination file and adds
  420.      * a carriage return if cr is true. It  assumes that the string is 
  421.      * already pointed to by pb.ioBuffer using the assignment 
  422.      * pb.ioBuffer := @Buf. It also assumes that GetTProc has already been
  423.      * called to get the required TProc.
  424.      *}
  425.     Procedure WriteString(str : str255; cr : boolean);
  426.         var
  427.             pct : integer;
  428.             err : OSErr;
  429.         begin
  430.         { Use the tprocs to transliterate between character sets }
  431.         TranslitString(str);
  432.         pb.ioReqCount := bufsize;
  433.         err := FileIO(FFWrite,tofs,@pb,statrec,trnpb);
  434.         { add the carriage return to the destination file } 
  435.         if cr and (err = noerr) then begin
  436.             buf[0] := 13;    {carriage return}
  437.             bufsize := 1;
  438.             { if translating to an MSDOS disk a line feed is also needed to
  439.               start a new line. }
  440.             if statrec^^.tranKind = tMCMS then begin
  441.                 buf[1] := 10;    { line feed }
  442.                 bufsize := 2;
  443.                 end;
  444.             pb.ioReqCount := bufsize;
  445.             err := FileIO(FFWrite,tofs,@pb,statrec,trnpb);
  446.             end;
  447.         { report any error that occurred while writing to the destination }
  448.         if err <> noerr then begin
  449.             reporterr(err,str_writing,statrec,trnpb);
  450.             CopyFile := err;
  451.             useResFile(oldres);
  452.             exit(copyFile)
  453.             end;
  454.         { compute how much of the translation has been completed for 
  455.           display in the status window }
  456.         datasize := datasize+length(str);
  457.         pct := datasize * 100 div statrec^^.srcSize;
  458.         if pct < 0 then pct := 0
  459.         else if pct > 100 then pct := 100;
  460.         { if user clicks on cancel }
  461.         if not CallStat('',pct,1,trnpb^.trnStatProc) then begin
  462.             CopyFile := trnCancel;
  463.             useResFile(oldres);
  464.             exit(copyFile);
  465.             end;
  466.         end;
  467.     
  468.     {* This procedure writes out the first line of the destination file 
  469.      * it tells how many strings there are to translate }
  470.     Procedure Header(numstr : integer);
  471.         var
  472.             oldres : integer;
  473.             str : str255;
  474.         begin
  475.         datasize := 0;
  476.         GetTProc;
  477.         pb.ioCompletion := NIL;
  478.         pb.ioRefNum := dstref;
  479.         pb.ioBuffer := @buf;
  480.         pb.ioPosMode := fsAtMark;
  481.         oldres := CurResFile;
  482.         useResFile(statRec^^.myfref);
  483.         GetIndString(str,statrec^^.myID,str_numstrings);
  484.         WriteString(str,false);
  485.         { convert the count of STR# resources to a string }
  486.         NumToString(numstr,str);
  487.         WriteString(str,true);
  488.         useResFile(oldres);
  489.         end;
  490.  
  491.     {* This procedure writes to the destination file a line stating the 
  492.      * string resource ID number 
  493.      *}
  494.     Procedure HeaderString(s,theID,numentries : integer; theName : str255);
  495.         var
  496.             oldres : integer;
  497.             str : str255;
  498.         begin
  499.         oldres := CurResFile;
  500.         useResFile(statRec^^.myfref);
  501.         { Insert a blank line }
  502.         WriteString('',true);
  503.         { Write the string 'String Resource Number ' }
  504.         GetIndString(str,statrec^^.myID,str_stringRes);
  505.         WriteString(str,false);
  506.         { convert the resource ID number to a string }
  507.         NumToString(theID,str);
  508.         WriteString(str,true);
  509.         { make the old resource the current one }
  510.         useResFile(oldres);
  511.         end;
  512.     
  513.     {* This procedure writes to the destination file one of the strings in
  514.      * a  STR# resource. It is called from the main body of CopyFile
  515.      *}
  516.     Procedure EntryString(str : str255; n : integer);
  517.         var
  518.             oldres : integer;
  519.             str2 : str255;
  520.         begin
  521.         writeString(str,true);
  522.         end;
  523.     
  524.     begin { Main body of CopyFile }
  525.     { save the current resource file to restore later }
  526.     oldres := CurResFile;
  527.     useResFile(srcref);
  528.     { get the number of STR# resources }
  529.     numstr := count1Resources('STR#');
  530.     { Write the number of STR# resources to the destination file }
  531.     Header(numstr);
  532.     for s := 1 to numstr do begin
  533.         { get the sth resource from the source file }
  534.         hstr := Get1IndResource('STR#',s);
  535.         if hstr = NIL then leave;
  536.         GetResInfo(hstr,theID,theType,theName);
  537.         { make numptr point to the same place as the master pointer
  538.           of the STR# resource. Since numptr is of a different type we 
  539.           use Pointer to avoid type conflicts. }
  540.         numptr := POINTER(hstr^);
  541.         { The first value in a STR# resource is the number of strings in 
  542.           the resource (an integer value). Since numptr is a ^integer, it 
  543.           is pointing to this value }
  544.         numentries := numptr^;
  545.         Headerstring(s,theID,numentries,theName);
  546.         { get each string in the resource and write it to the destination 
  547.           file }
  548.         for n := 1 to numentries do begin
  549.             GetIndString(str,theID,n);
  550.             EntryString(str,n);
  551.             end;
  552.         end;
  553.     { if we have been using a tproc tell it that we have finished the 
  554.       translation }
  555.     if tproc <> NIL then begin
  556.         tpb.verb := transdone;
  557.         if tproc^ = NIL then loadresource(POINTER(tproc));
  558.         if CallTProc(tpb,tproc) <> noerr then ;  
  559.         end;
  560.     useResFile(oldres);
  561.     CopyFile := noerr;
  562.     end; { CopyFile }
  563.  
  564.  
  565. {*******************************   DoAppear   *******************************
  566.  * DoAppear is called in response to a trn_APPEAR message which occurs when    *
  567.  * a new disk has been selected which has caused this routine to appear in     *
  568.  * its menu.  We do not change appearance in the menu, except to clear any    * 
  569.  * gray bits that may have been set. Returns NoErr as function result.        *
  570.  * Some functions may use this procedureto define some global data            *
  571.  * (such as source or destination FS, etc ).                                *
  572.  * Notice how the grey bit is turned off. First we create this bit value    *
  573.  * with all the bits except for the grey bit on (-1 = $FFFFFFFF) Then we     *
  574.  * bit and this with the current status, any  high bits in the current         *
  575.  * status remain high and none that are not are activated. This is called    *
  576.  * masking, and is the most effecient method for changing individual status *
  577.  * bits.                                                                    *
  578.  ***************************************************************************}
  579. Function  DoAppear(trnpb : trnptr; statRec : statHndl) : longint;
  580.     begin
  581.     statRec^^.myStatus := band(statRec^^.myStatus,-1-trnGray);
  582.     DoAppear := noErr;
  583.     end; { DoAppear }
  584.  
  585. {********************************** DoFileConvert ***************************
  586. * Called when the translator receives a trn_FILE. Result = Accept,unAccept, *
  587. * or Cancel.                                                                *
  588. * This function creates the necessary files for the translation to occur.   *
  589. * The actual translation is done by another function CopyFile.                *
  590. * Notice the care used in regards to duplicate file names, particularly the *
  591. * creation of an intermediate file when copying in place (ie replacing the  *
  592. * source with the destination file). 
  593. ****************************************************************************}
  594. Function  DoFileConvert(statRec : statHndl; trnPB : trnPtr) : longint;
  595.     var
  596.         err,err2 : OSErr;
  597.         srcopened,dstcreated,dstopened,tempfile : boolean;
  598.         pb : HParamBlockRec;
  599.         pbold,pbnew : WDPBRec;
  600.         catpb : CInfoPBRec;
  601.         srcref,dstref : integer;
  602.         frstr,tostr : str255;
  603.         str : str255;
  604.     begin
  605.     DoFileConvert := unaccept;
  606.     { Note how we always use the same recognize for trn_File and trn_Recognize }
  607.     if RecogFile(statRec,trnPB) = accept then begin
  608.         DoFileConvert := accept;
  609.         srcopened := false;
  610.         dstcreated := false;
  611.         dstopened := false;
  612.         tempfile := false;
  613.         tostr := trnPB^.trnnames^^.names[1]; { source file name }
  614.         frstr := trnPB^.trnnames^^.names[0]; { destination file name }
  615.         err := noerr;
  616.         { create the destination file }
  617.         if err = noerr then with pb do begin
  618.             ioNamePtr := @tostr;
  619.             pb.ioFVersNum := 0;
  620.             err := FileOp(FFCreate,toFS,@pb,statrec,trnpb);
  621.             { if the file already exists }
  622.             if err = dupfNErr then begin
  623.                 { check to see if it is the source file }
  624.                 if (trnpb^.trnfrID = trnpb^.trntoID)
  625.                         and (trnpb^.trnfrVRef = trnpb^.trntoVRef)
  626.                         and (trnpb^.trnfrpar = trnpb^.trntopar)
  627.                         and (tostr = frstr) then begin
  628.                     { if it is then create a temporary file to hold the tran-
  629.                       slation }
  630.                     tostr := '$$$@FE-TEMP$$$';
  631.                     repeat
  632.                         { increment the fourth letter by one until we get  }
  633.                         { a unique name for the temporary file }
  634.                         tostr[4] := CHR(ORD(tostr[4])+1);
  635.                         err := FileOp(FFCreate,toFS,@pb,statrec,trnpb);
  636.                         until err <> dupfNErr;
  637.                     { if another error occurred then do not translate }
  638.                     if err <> noerr then err := fBsyErr
  639.                     else tempfile := true;
  640.                     end
  641.                 { if the destination is not the same as the source then delete
  642.                   the current file and create a new destination file }
  643.                 else begin
  644.                     ioNamePtr := @tostr;
  645.                     ioFVersNum := 0;
  646.                     err2 := FileOp(FFDelete,toFS,@pb,statrec,trnpb);
  647.                     if err2 = noerr then begin
  648.                         ioNamePtr := @tostr;
  649.                         pb.ioFVersNum := 0;
  650.                         err := FileOp(FFCreate,toFS,@pb,statrec,trnpb);
  651.                         end;
  652.                     end;
  653.                 end;
  654.             { if the last operation was successful then the destination file
  655.               was created }
  656.             if err = noerr 
  657.                 then dstcreated := true
  658.                 else reportErr(err,str_creating,statRec,trnPB);
  659.             end;
  660.         
  661.         { if a Mac to Mac translation }
  662.         if statRec^^.trankind = tMCMC then begin
  663. {* Note: before doing a SetFInfo it is a good idea make sure that there is *
  664.  * valid information in all param block fields so do a GetFInfo first      *}
  665.             if err = noerr then with catpb do begin
  666.                 ioNamePtr := @tostr;
  667.                 ioFDirIndex := 0;
  668.                 err := FileOp(FFGetFInfo,toFS,@catpb,statrec,trnpb);
  669.                 { If the destination gives a bad param block try the source }
  670.                 if err <> noerr then begin
  671.                     ioNamePtr := @frStr;
  672.                     ioFVersNum := 0;
  673.                     err := FileOp(FFGetFInfo,fromFS,@catpb,statrec,trnpb);
  674.                     err := noerr;
  675.                     end;
  676.                 end;
  677.             { Set the destination file type and creator }
  678.             if err = noerr then with catpb do begin
  679.                 ioNamePtr := @tostr;
  680.                 ioflFndrInfo.fdtype := 'TEXT';
  681.                 ioflFndrInfo.fdcreator := statrec^^.ftype;
  682.                 err := FileOp(FFSetFInfo,toFS,@catpb,statrec,trnpb);
  683.                 if err <> noerr then reportErr(err,str_setfinfo,statRec,trnPB);
  684.                 err := noerr;
  685.                 end;
  686.             end;
  687.         { For all file systems  open the destination }
  688.         if err = noerr then with pb do begin
  689.             ioNamePtr := @tostr;
  690.             if statrec^^.tranKind = tMCPD
  691.                 then ioPermssn := 0
  692.                 else ioPermssn := fsWrPerm;
  693.             ioMisc := NIL;
  694.             err := FileOp(FFOpen,toFS,@pb,statrec,trnpb);
  695.             if err = noerr then begin
  696.                 dstopened := true;
  697.                 dstref := ioRefNum;
  698.                 end
  699.             else reportErr(err,str_opendst,statRec,trnPB);
  700.             end;
  701.         { check to see if the file is already opened }
  702.         if err = noerr then with catpb do begin
  703.             ioNamePtr := @frstr;
  704.             ioFVersNum := 0;
  705.             ioFDirIndex := 0;
  706.             err := FileOp(FFGetFInfo,fromFS,@catpb,statrec,trnpb);
  707.             if err <> noerr then reportErr(err,str_getfinfo,statRec,trnPB);
  708.             end;
  709.         if (err = noerr) and (band(catpb.ioFlAttrib,$04) = 0) then with pb do begin
  710.             pbold.ioCompletion := NIL;
  711.             pbold.ioNamePtr := NIL;
  712.             err := PBHGetVol(@pbold,false);
  713.             if err = noerr then with pbnew do begin
  714.                 ioCompletion := NIL;
  715.                 ioNamePtr := NIL;
  716.                 ioVRefNum := trnpb^.trnfrvref;
  717.                 ioWDDirID := trnpb^.trnfrpar;
  718.                 err := PBHSetVol(@pbnew,false);
  719.                 end;
  720.             if err = noerr then begin
  721.                 srcref := OpenResFile(trnpb^.trnNames^^.names[0]);
  722.                 err := PBHSetVol(@pbold,false);
  723.                 end;
  724.             { if the resource fork of the source could not be opened then exit }
  725.             if (err = noerr) and (srcref <= 0) then err := fnferr;
  726.             if err = noerr then begin
  727.                 srcopened := true;
  728.                 end
  729.             else reportErr(err,str_opendst,statRec,trnPB);
  730.             end
  731.         else if err = noerr then srcRef := catpb.ioFRefNum;
  732.         { If opened destination get size of source strings, this value is saved in 
  733.             statrec^^.srcsize after opening the source file *}
  734.         if err = noerr then with catpb do begin
  735.             statrec^^.srcsize := GetStrSize(srcref);
  736.             end;
  737.         
  738.         { If no errors so far then translate the file }
  739.         GetIndString(str,statrec^^.myID,str_copying);
  740.         if not CallStat(str,0,1,trnpb^.trnStatProc) then err := trnCancel;
  741.         if err = noerr then err := copyFile(srcref,dstref,statrec,trnpb);
  742.         if not CallStat('',100,1,trnpb^.trnStatProc) then err := trnCancel;
  743.  
  744.         { Close the files and erase any temporary files }
  745.         if srcopened then with pb do begin
  746.             CloseResFile(srcref);
  747.             end;
  748.         if dstopened then with pb do begin
  749.             ioRefNum := dstref;
  750.             err2 := FileIO(FFClose,tofs,@pb,statrec,trnpb);
  751.             end;
  752.         { If an error occurred during translation than delete the destination
  753.           file, it is not valid }
  754.         if (err <> noerr) and dstcreated then with pb do begin
  755.             ioNamePtr := @tostr;
  756.             ioFVersNum := 0;
  757.             err2 := FileOp(FFDelete,toFS,@pb,statrec,trnpb);
  758.             end;
  759.         { if a translation in place was completed then delete the source and
  760.           rename the destination with the source name }
  761.         if (err = noerr) and tempfile then with pb do begin
  762.             ioNamePtr := @frstr;
  763.             ioFVersNum := 0;
  764.             err2 := FileOp(FFDelete,toFS,@pb,statrec,trnpb);
  765.             if err2 <> noerr then reportErr(err2,str_delsrc,statRec,trnPB);
  766.             if err2 = noerr then begin
  767.                 ioNamePtr := @tostr;
  768.                 ioFVersNum := 0;
  769.                 ioMisc := @frstr;
  770.                 err2 := FileOp(FFRename,toFS,@pb,statrec,trnpb);
  771.                 if err2 <> noerr then reportErr(err2,str_rendst,statRec,trnPB);
  772.                 end;
  773.             end;
  774.         if err = trncancel then DoFileConvert := trnCancel;
  775.         end;
  776.     end; { DoFileConvert }
  777.     
  778.  
  779. {************************************** DoFinish ****************************
  780.  * Called when transltor receives an trn_FINIS.                                *
  781.  * DoFinish cleans up any global variables that might have been allocated.    *
  782.  * ALWAYS returns NoErr. It is only called when execution of AFE is         *
  783.  * terminated (ie. you hit quit ).                                            * 
  784.  ***************************************************************************} 
  785.  Function  DoFinish(VAR translateData : handle) : OSErr;
  786.     begin
  787.     DoFinish := noErr;
  788.     if translateData <> NIL then disposHandle(translateData);
  789.     translateData := NIL;
  790.     end;
  791.  
  792. {************************************** DoInit ******************************
  793.  * Called whenever a translator receives a trn_INIT message. This happens    *
  794.  * when translators are imported to other menus as well as at startup.        *
  795.  * DoInit initializes the variables we need.  It allocates a relocatable    *
  796.  * block of memory and puts the handle in translateData. It determines the    *  
  797.  * source and dest file system and sets up the default parameters.  It        * 
  798.  * returns noErr if all goes well, and a negative result otherwise.            *
  799.  ***************************************************************************}
  800. Function  DoInit(VAR translateData,self : handle; trnpb : trnPtr) : longint;
  801.     var
  802.         theID : integer; theType : restype; namefr,nameto,myname : str255;
  803.         str : str255;
  804.         dstnick,srcnick : halfResType;
  805.         err : OSErr;
  806.         statRec : StatHndl;
  807.         kind : integer;
  808.         srcHandle,dstHandle : handle;
  809.         len : integer;
  810.         thefref : integer;
  811.     begin
  812.     {* get handles of source and dest file systems 
  813.      * Note: GetResource returns NoErr even if it does not find the 
  814.      * resource.  This is why one must check for NIL handles as well as
  815.      * ResError.}
  816.     srcHandle := GetResource(foreignFS,trnpb^.trnfrID);
  817.     err := ResError;
  818.     if (err = noErr) and (srcHandle = NIL) then err := resNotFound;
  819.     if err = noerr then begin
  820.         dstHandle := GetResource(foreignFS,trnpb^.trntoID);
  821.         err := ResError;
  822.         if (err = noErr) and (dstHandle = NIL) then err := resNotFound;
  823.         end;
  824.     
  825.     {* get nickname of source file system = The last two characters of
  826.      * the file system name; MC, MS, PD. }
  827.     if err = noerr then begin
  828.         GetResInfo (srcHandle, theID, theType, namefr);
  829.         err := ResError;
  830.         end;
  831.     if err = noErr then begin
  832.         len := length(namefr);
  833.         if len <= 2 then err := bdNamErr;
  834.         end;
  835.     if err = noErr then begin
  836.         srcnick[1] := namefr[len-1]; srcnick[2] := namefr[len];
  837.         if (srcnick <> 'PD') and (srcnick <> 'MS') and (srcnick <> 'MC')
  838.             then err := extFSErr;
  839.         end;
  840.         
  841.     {* get nickname of destination file system *} 
  842.     if err = noerr then begin
  843.         GetResInfo (dstHandle, theID, theType, nameto);
  844.         err := ResError;
  845.         end;
  846.     if err = noErr then begin
  847.         len := length(nameto);
  848.         if len <= 2 then err := bdNamErr;
  849.         end;
  850.     if err = noErr then begin
  851.         dstnick[1] := nameto[len-1]; dstnick[2] := nameto[len];
  852.         if (dstnick <> 'PD') and (dstnick <> 'MS') and (dstnick <> 'MC')
  853.             then err := extFSErr;
  854.         end;
  855.  
  856.     {*    get information about translator. Keeping the file reference number
  857.      *     allows one to switch the resource file in use to one's own if it is
  858.      *    not the current one.    
  859.      *}
  860.     if err = noerr then begin
  861.         getResInfo(self,theID,thetype,myname);
  862.         err := ResError;
  863.         end;
  864.     if err = noerr then begin
  865.         theFRef := homeResFIle(self);
  866.         err := ResError;
  867.         end;
  868.     
  869.     {* determine  kind of translation. This translator only supports tran-
  870.      * slation from the Macintosh file system. If we are not in one of these
  871.      * menus then generate an error.
  872.      *}
  873.     if err = noErr then begin
  874.         if      (srcnick='MC') and (dstnick = 'MC') then kind := tMCMC
  875.         else if (srcnick='MC') and (dstnick = 'PD') then kind := tMCPD
  876.         else if (srcnick='MC') and (dstnick = 'MS') then kind := tMCMS
  877.         else err := extFSerr;
  878.         end;
  879.     
  880.     {* get global data space. Why do we make statrec a pointer to handle can
  881.     you even do this?!? *}
  882.     if err = noErr then begin
  883.         translateData := NewHandle(sizeof(statusRec));
  884.         statrec := POINTER(translateData);
  885.         err := MemError;
  886.         end;
  887.     
  888.     {* set up default settings *}
  889.     if err = noErr then with statRec^^ do begin
  890.         { Check menu item (make it active) and set the About bit }
  891.         myStatus := trnActive + trnAbout;
  892.         { the ID number of the translator resource }
  893.         myID := theID;
  894.         { the file reference number of the translator file }
  895.         myFref := theFref;
  896.         { the type of translation (Mac to Mac, etc.) }
  897.         trankind := kind;
  898.         { default file type is MacWrite }
  899.         ftype := 'MACA';
  900.         { default translation is into a MacWrite file }
  901.         fkind := tMacWrite;
  902.         { Handles to the source and destination file system (resources). }
  903.         frHandle := srcHandle;
  904.         toHandle := dstHandle;
  905.         end;
  906.     
  907.     if err <> noerr then begin
  908.         GetIndString(str,theID,str_error);
  909.         CallErrLog(str,false,false,trnpb^.trnlogproc);
  910.         GetIndString(str,theID,str_initing);
  911.         CallLog(str,false,false,trnPB^.trnlogproc);
  912.         CallLog(myname,false,false,trnPB^.trnlogproc);
  913.         GetIndString(str,theID,str_period);
  914.         CallLog(str,true,false,trnPB^.trnlogproc);
  915.         { If translator is not in a valid menu  }
  916.         if err = extFSerr then begin
  917.             GetIndString(str,theID,str_cant);
  918.             CallLog(str,false,false,trnPB^.trnlogproc);
  919.             CallLog(copy(namefr,1,length(namefr)-2),false,false,trnPB^.trnlogproc);
  920.             GetIndString(str,theID,str_to);
  921.             CallLog(str,false,false,trnPB^.trnlogproc);
  922.             CallLog(copy(nameto,1,length(nameto)-2),false,false,trnPB^.trnlogproc);
  923.             GetIndString(str,theID,str_period);
  924.             CallLog(str,true,false,trnPB^.trnlogproc);
  925.             end;
  926.         end;
  927.         
  928.     DoInit := err;
  929.     end; { DoInit }
  930.  
  931. {*******************************   DoName    ********************************
  932.  * Called when the translator receives a trn_NEWNAME message                *
  933.  * trn_NEWNAME is passed a trnPTR in PARAM.  It should check the file        *
  934.  * specified as the source and return either NOERR or UNACCEPT as the        * 
  935.  * function result, depending on whether the file matches the criteria for    *
  936.  * acceptance by this routine (it can skip checking for acceptance if the    *
  937.  * trnTESTED field is true -- in that case, the trnACCEPTED field indicates *
  938.  * whether this file was previously accepted). If acceptable, then             *
  939.  * trn_NEWNAME should return a suggested new name for the destination file,    *
  940.  * and set the field trnNAMES.NAMECNT to 1.  On those occasions when more    * 
  941.  * than one destination file will be produced, the name handle should be    *
  942.  * expanded and trnNAMES.NAMECNT should be increased appropriately.            *
  943.  ***************************************************************************}
  944. Function  DoName(statRec : statHndl; trnPB : trnPtr) : longint;
  945.     var
  946.         temp : longint;
  947.         pb : HParamBlockRec;
  948.         err : OSErr;
  949.         str : str255;
  950.     begin
  951.     DoName := unaccept;
  952.     if RecogFile(statRec,trnPB) = accept then begin
  953.         str := trnpb^.trnNames^^.names[0];
  954.         trnpb^.trnNames^^.NameCnt := 1;
  955.         pb.ioNamePtr := @str;
  956.         pb.ioDirID := trnpb^.trnToPar;
  957.         pb.ioVRefNum := trnPb^.trnToVRef;
  958.         err := FileOp(FFMakeFName,toFS,@pb,statrec,trnpb);
  959.         if err = noerr then begin
  960.             trnpb^.trnNames^^.names[1] := str;
  961.             DoName := accept;
  962.             end;
  963.         end;
  964.     end; { DoName }
  965.  
  966. {********************************  FileIO   *********************************
  967.  * Called by CopyFile, DoFileConvert                                        *
  968.  * This is a utility function that does the repetitive actions for            *
  969.  * FFREAD, FFWRITE, and FFCLOSE. The Calling procedure provides:            *
  970.  *            ioRefNum                                                        *
  971.  *            ioposMode†, ioposOffset†                                        *
  972.  *            ioReqCount†, ioBuffer †                                            *
  973.  *                                                                            *
  974.  *          † for READ and WRITE only                                            *                                            
  975.  *                                                                            *
  976.  ***************************************************************************}
  977. Function  FileIO(ff,fs : integer; pb : HParmBlkPtr; statrec : StatHndl; 
  978.                     trnPB : trnPtr) : OSErr;
  979.     var
  980.         err : OSErr;
  981.     begin
  982.     pb^.ioCompletion := NIL;
  983.     err := noErr;
  984.     if fs = fromFS
  985.         then err := CallFS(ff,trnpb^.trnfrData,POINTER(pb),false,statrec^^.frHandle)
  986.         else err := CallFS(ff,trnpb^.trntoData,POINTER(pb),false,statrec^^.toHandle);
  987.     FileIO := err;
  988.     end; { FileIO }
  989.  
  990. {********************************  FileOp   *********************************
  991.  * Called by DoFileConvert, DoFileName, RecogFile                            * 
  992.  * for FFOPEN, FFGETFINFO, FFGETCATINFO, FFSETCATINFO, FFSETFINFO, FFRENAME,*
  993.  * FFDELETE, FFCREATE, FFGETXCATINFO, FFSETXCATINFO, FFMAKEFNAME            * 
  994.  *    Calling procedure provides (in the pb variable):                        *
  995.  *            ioMisc,ioPermssn,ioNamePtr -- FFOPEN                            *
  996.  * This function provides the part of the CallFS function that does not      *
  997.  * change for the calls listed above. It eliminates having to repeat it for *
  998.  * every one of the calls.                                                    *
  999.  ***************************************************************************}
  1000. Function  FileOp(ff,fs : integer; pb : HParmBlkPtr; statrec : StatHndl; trnPB : trnPtr) : OSErr;
  1001.     { ff = file system command, fs = source or destination file  }
  1002.     var
  1003.         err : OSErr;
  1004.     begin
  1005.     with pb^ do begin
  1006.         ioCompletion := NIL;
  1007.         if fs = fromFS then begin
  1008.             ioVRefNum := trnpb^.trnfrVRef;
  1009.             ioDirID := trnpb^.trnfrPar;
  1010.             err := CallFS(ff,trnpb^.trnfrData,POINTER(pb),false,statrec^^.frHandle);
  1011.             end
  1012.         else begin { perfrom operation on the source file }
  1013.             ioVRefNum := trnpb^.trntoVRef;
  1014.             ioDirID := trnpb^.trntoPar;
  1015.             err := CallFS(ff,trnpb^.trntoData,POINTER(pb),false,statrec^^.toHandle);
  1016.             end;
  1017.         end;
  1018.     FileOp := err;
  1019.     end; { FileOp }
  1020.  
  1021. Function  GetStrSize(fref : integer) : longint;
  1022.     var
  1023.         oldres : integer;
  1024.         size : longint;
  1025.         h : handle;
  1026.         numstr,s : integer;
  1027.     begin
  1028.     oldres := curResFile;
  1029.     useResFile(fref);
  1030.     setResload(false);
  1031.     numstr := count1Resources('STR#');
  1032.     size := 0;
  1033.     for s := 1 to numstr do begin
  1034.         h := Get1IndResource('STR#',s);
  1035.         size := size + MaxSizeRsrc(h);
  1036.         end;
  1037.     setResLoad(true);
  1038.     useResFile(oldres);
  1039.     GetStrSize := size;
  1040.     end;
  1041.  
  1042. {******************************** RecogFile *********************************
  1043.  * Called when trasnlator receives trn_Recognize.                            *
  1044.  * It is also called by DoName and DoFileConvert.                            *
  1045.  * RecogFile is passed a trnPTR and status record.  It should check the file*
  1046.  * specified as the source and return either ACCEPT or UNACCEPT as the        *
  1047.  * function result, depending on whether the file matches the criteria for    *
  1048.  * acceptance by this routine. Notice how we do not log errors during that  *
  1049.  * may occur in this function. We only want to know if this translator can  *
  1050.  * translate this file or not, if it can't for any reason then we do not    *
  1051.  * accept the file.                                                            *
  1052.  ***************************************************************************}
  1053. Function  RecogFile(statRec : statHndl; trnPB : trnPtr) : longint;
  1054.     var
  1055.         err : OSErr;
  1056.         pb : HParamBlockRec;
  1057.         pbnew,pbold : WDPBRec;
  1058.         temp : OSType;
  1059.         size,readsize : longint;
  1060.         fref, num : integer;
  1061.         srcopened : boolean;
  1062.         oldres : integer;
  1063.     begin
  1064.     {* check if the file's already been tested *}
  1065.     RecogFile := unaccept;
  1066.     if trnPB^.trnTested then begin
  1067.         if trnPB^.trnAccepted then RecogFile := accept;
  1068.         exit(RecogFile);
  1069.         end;
  1070.     
  1071.     {* check whether we have a resource fork or no *}
  1072.     pb.ioNamePtr := @trnpb^.trnNames^^.names[0];
  1073.     pb.ioFDirIndex := 0;
  1074.     err := FileOp(FFGetFInfo,fromFS,@pb,statrec,trnpb);
  1075.     if err <> noerr then exit(RecogFile); { don't log errors during recognition }
  1076.     if pb.ioFlRPyLen = 0 then exit(RecogFile);
  1077.     
  1078.     srcopened := false;
  1079.     if band(pb.ioFlAttrib,$04) = 0 then begin { if already opened, don't reopen }
  1080.         {* now we have to check things out via the resource manager *}
  1081.             {* first: set up the volume because the resource manager doesn't allow volume
  1082.                     AND directory specification *}
  1083.         pbold.ioCompletion := NIL;
  1084.         pbold.ioNamePtr := NIL;
  1085.         err := PBHGetVol(@pbold,false);
  1086.         if err <> noerr then exit(RecogFile);
  1087.         with pbnew do begin
  1088.             ioCompletion := NIL;
  1089.             ioNamePtr := NIL;
  1090.             ioVRefNum := trnpb^.trnfrvref;
  1091.             ioWDDirID := trnpb^.trnfrpar;
  1092.             err := PBHSetVol(@pbnew,false);
  1093.             if err <> noerr then exit(RecogFile);
  1094.             end;
  1095.         fref := OpenResFile(trnpb^.trnNames^^.names[0]);
  1096.         err := PBHSetVol(@pbold,false);
  1097.         { if the resource fork of the source could not be opened then exit }
  1098.         if fref <= 0 then exit(RecogFile);
  1099.         srcopened := true;
  1100.         end
  1101.     else fref := pb.ioFRefNum;
  1102.     oldres := CurResFile;
  1103.     useResFile(fref);
  1104.     num := count1Resources('STR#');
  1105.     useResFile(oldres);
  1106.     if num > 0
  1107.         then RecogFile := accept;
  1108.     if srcopened then begin
  1109.         CloseResFile(fref);
  1110.         end;
  1111.     
  1112.     end; { RecogFile }
  1113.  
  1114. {******************************** ReportErr *********************************
  1115. * Called whenever an error occurs that must be reported to the user log, ie *
  1116. * it is used by almost all of the procedures.                                *
  1117. * Notice how part of the error message is reported using resources stored   *
  1118. * in the AFE resource fork (for err <0 and >-85).  AFE includes some stan-  *
  1119. * dard strings for these errors, check them out with ResEdit to see if they *
  1120. * fit in your error messages as well. They are in the STR# ID=150 resource    *                                        *
  1121. ****************************************************************************}
  1122. Procedure ReportErr(err,doing : integer; statRec : statHndl; trnPB : trnPtr);
  1123.     { err = error code (usually a File manager code,
  1124.       doing = the action attempted that caused the error, one of the str_
  1125.        constants declared at the top of this unit }
  1126.     var
  1127.         Str : str255;
  1128.         oldres : integer;
  1129.     begin
  1130.     { save the AFE file ref number of the AFE resource file }
  1131.     oldres := curResFile;
  1132.     { use the translator resource file }
  1133.     useResFile(statRec^^.myFRef);
  1134.     GetIndString(str,statrec^^.myID,str_error);
  1135.     CallErrLog(str,false,true,trnPB^.trnlogproc);
  1136.     GetIndString(str,statrec^^.myID,doing);
  1137.     CallErrLog(str,false,true,trnPB^.trnlogproc);
  1138.     useResFile(oldres);
  1139.     { if appropriate use the error string from the AFE resource STR#150 }
  1140.     if (err < 0) and (err > -85)
  1141.         then GetIndString(str,150,-err)
  1142.         else GetIndString(str,150,5);
  1143.     CallErrLog(str,true,true,trnpb^.trnlogproc);
  1144.     end; { ReportErrLog }
  1145.  
  1146. {********************************* TranStr **********************************
  1147. * This is the function that provides the interaction between AFE and the    *
  1148. * translator. It ALWAYS has the SAME number and types of parameters.        *
  1149. * INPUT     : Message - this integer describes the opertation requested by  *
  1150. *                AFE for a complete listing of these operations see the         *
  1151. *                constants under the "Conversion Routine Commands" heading    *
  1152. *              TranslateData - this is either the default settings for this    * 
  1153. *                translator, or a handle to some global data the translator    *
  1154. *                has allocated.                                                *
  1155. *              Param    - Varies with the message. Usually a pointer to info on *
  1156. *                source and destination files, or names of translated files.    *
  1157. *              Self - this is a handle to the translation routine itself.    *
  1158. *                It is used to lock the routine in memory while it is in use.*
  1159. * OUTPUT     : NONE                                                            *
  1160. * RESULT    : Varies with the message.  Usually the status of a certain oper*
  1161. *                ation. If AFE does not explicitly require a result the tran-*
  1162. *                slator must return a zero.                                    *
  1163. ****************************************************************************}
  1164. function TranStr(Message : integer; VAR translateData : Handle;
  1165.         Param : longint; Self : handle) : longint;
  1166.     var
  1167.         trnpb : trnPtr;
  1168.         statRec,statrec2 : statHndl;
  1169.         oldres : integer;
  1170.         h : handle;
  1171.         err : OSErr;
  1172.     begin
  1173.     hlock(self);
  1174.     trnpb := POINTER(Param);
  1175.     statRec := POINTER(translateData);
  1176.     case Message of
  1177.         trn_Init    : begin
  1178.             TranStr := DoInit(translateData,self,trnpb);
  1179.             end;
  1180.             
  1181.         trn_Finis   : begin
  1182.             TranStr := DoFinish(translateData);
  1183.             end;
  1184.             
  1185.         trn_Appear    : begin
  1186.             TranStr := DoAppear(trnpb,statRec);
  1187.             end;
  1188.             
  1189.         trn_Disappear   : begin
  1190.             {* trn_DISAPPEAR cleans up any global variables that might have
  1191.              * been allocated by trn_APPEAR.  ALWAYS returns NoErr.
  1192.              *}
  1193.             TranStr := noerr;
  1194.             end;
  1195.             
  1196.         trn_Get     : begin
  1197.             {* trn_GET returns the current status of this routine as the
  1198.              * function result.
  1199.              *}
  1200.             TranStr := statRec^^.myStatus;
  1201.             end;
  1202.             
  1203.         trn_Set        : begin
  1204.             {* trn_SET sets the status flag of this routine using the
  1205.              * value in PARAM. The new status flag is returned as the
  1206.              * function result. 
  1207.              *}
  1208.              statRec^^.myStatus := param;
  1209.              TranStr := param;
  1210.             end;
  1211.             
  1212.         trn_Active     : begin
  1213.             TranStr := Activate(statRec,trnPB);
  1214.             end;
  1215.             
  1216.         trn_Inactive    : begin
  1217.             {* trn_INACTIVE indicates that the user wishes to UNcheck this
  1218.              * menu item.  The routine just clears the active bit in the
  1219.              * flags, and then returns the new status flag as the
  1220.              * function result.
  1221.              *}
  1222.              statRec^^.myStatus := band(statRec^^.myStatus,-1-trnActive);
  1223.              TranStr := statRec^^.myStatus;
  1224.             end;
  1225.             
  1226.         trn_Recognize    : begin
  1227.              TranStr := RecogFile(statRec,trnpb);
  1228.              end;
  1229.              
  1230.         trn_NewName    : begin
  1231.              TranStr := DoName(statRec,trnpb);
  1232.              end;
  1233.              
  1234.         trn_File    : begin
  1235.             {* trn_FILE is passed a trnPTR in PARAM.  It should check
  1236.              * the file specified as the source and return either NOERR
  1237.              * or UNACCEPT as the function result, depending on whether
  1238.              * the file matches the criteria for acceptance by this
  1239.              * routine.  If acceptable, then trn_FILE should do the actual
  1240.              * translations, using the name (or possibly names) specified
  1241.              * in the name handle.  Any errors encountered during translations
  1242.              * should be reported to the user log.  Periodically, the
  1243.              * status procedure should be called with a (possibly empty)
  1244.              * status message and a number between 0 and 100 indicating
  1245.              * the percentage complete.  This routine will return TRUE
  1246.              * most of the time, but can return FALSE if the user has
  1247.              * pressed the CANCEL button on the status panel.  Because the
  1248.              * user can press CANCEL, it is requested that trn_FILE call
  1249.              * the status procedure as often as necessary to achieve some
  1250.              * measure of reasonable feedback.
  1251.              *}
  1252.              TranStr := DoFileConvert(statRec,trnpb);
  1253.             end;
  1254.         trn_Load     : begin
  1255.             {*
  1256.              * Do a GETRESOURCE for all of the resources that you might
  1257.              * need during a translation.  This does not guarantee that
  1258.              * a "floppy shuffle" won't be needed, just helps the odds.
  1259.              * Load the most likely to be used resources last so they will
  1260.              * be the least likely to be purged.
  1261.              *}
  1262.              oldres := curResFile;
  1263.              useResFile(statrec^^.myFRef);
  1264.              h := getResource('ICON',statrec^^.myID);
  1265.              h := getResource('ICON',statrec^^.myID+1);
  1266.              h := getResource('ICON',statrec^^.myID+2);
  1267.              h := getResource('ICON',statrec^^.myID+3);
  1268.              h := getResource('DITL',statrec^^.myID);
  1269.              h := getResource('DLOG',statrec^^.myID);
  1270.              h := getResource('STR#',statrec^^.myID);
  1271.              useResFile(oldres);
  1272.              { don't bother bringing in the ABOUT text }
  1273.              TranStr := 0;
  1274.             end;
  1275.         trn_About    : begin
  1276.             {*
  1277.              * If we want to tell the user about ourselves, we can put up
  1278.              * our own dialog (in which case we return zero).  If we want
  1279.              * nothing done, we can return -1, whereupon Apple File Exch will
  1280.              * inform the user that no information is available.
  1281.              * If we want Apple File Exch to display the information, we can give
  1282.              * it a (positive) resource ID of a TEXT resource containing
  1283.              * information about us.
  1284.              *}
  1285.              TranStr := statrec^^.myID;
  1286.              end;
  1287.         trn_GetSettings : begin
  1288.             {*
  1289.              * With this message, Apple File Exch is requesting a handle filled
  1290.              * with data that can be stored in a document.  Apple File
  1291.              * Exchange allows the user to save and restore default settings
  1292.              * ("preferences", if you will) so that the user can launch
  1293.              * the program and have each translation be in a state that
  1294.              * they are familiar with.  We have to do the NEWHANDLE call
  1295.              * to create a handle of the correct size, Apple File Exch will
  1296.              * dispose it later.  If this call is not supported, return
  1297.              * NIL or some (negative) error code.
  1298.              *}
  1299.              h := translateData;
  1300.              { Create a new handle that points to a COPY of the global data }
  1301.              err := HandToHand(h); { see Inside Mac vol II, p374 for details }
  1302.              if err = noerr
  1303.                  then TranStr := ORD4(h)
  1304.                  else TranStr := err;
  1305.              end;
  1306.         trn_SetSettings : begin
  1307.             {*
  1308.              * With this message, Apple File Exch is passing a handle filled
  1309.              * with data that indicates a default setting.  Apple File Exchange
  1310.              * allows the user to save and restore default settings
  1311.              * ("preferences", if you will) so that the user can launch
  1312.              * the program and have each translation be in a state that
  1313.              * they are familiar with.  Apple File Exch will dispose of this
  1314.              * handle later (do not do so yourself).  If this call is 
  1315.              * not supported, return NIL or some (negative) error code.
  1316.              *}
  1317.             h := POINTER(param);
  1318.             { If for some reason AFE does not send a pointer to the correct
  1319.               data then do not change the current set up }
  1320.             if GetHandleSize(h) <> sizeof(statusRec) then TranStr := 0
  1321.             else with statrec^^ do begin
  1322.                 statrec2 := POINTER(h);
  1323.                 mystatus := statrec2^^.mystatus;
  1324.                 ftype := statrec2^^.ftype;
  1325.                 fkind := statrec2^^.fkind;
  1326.                 end;
  1327.             end;
  1328.         end;
  1329.     hunlock(self);
  1330.     hpurge(self);
  1331.     end;
  1332.  
  1333. end.